const Mongo = require('mongodb');
/**
 * 数据库驱动
 */
module.exports = class DbDriver {
    constructor(options) {
        if (!options.capacity) options.capacity = 30;
        Object.assign(this, options);
        if (options.db) this._connstr = options.db.toString();
        this._pool = { capacity: options.capacity };
    }

    /**
     * 将指定的字符串Id返回ObjectID类型
     * @param {string} idStr 
     */
    static id(idStr) {
        if (!idStr) return null;
        if (idStr instanceof Mongo.ObjectID) return idStr;
        if (Mongo.ObjectId.isValid(idStr)) return Mongo.ObjectID(idStr);
        return idStr;
    }

    /** 生成一个新的ObjectID值 */
    static genId() {
        return Mongo.ObjectID.generate();
    }

    /**
     * 从指定驱动的连接池获取一个Db
     * @param {object} driver 数据库驱动对象
     */
    static getDb(driver) {
        var p = new DbDriver({}); // 借用一下类型而已
        if (driver) p = driver;
        return p.conn();
    }

    async onConnecting(idx) {
        return new Promise((resolve, reject) => {
            //console.debug(`connecting db with ${idx}.`);
            Mongo.MongoClient.connect(this._connstr, { useNewUrlParser: true, useUnifiedTopology: true }).then(client => {
                resolve(client);
                //console.debug(`connect db success with ${idx}.`);
            }).catch(err => {
                console.error(`connect db fail due ${err.message} with ${idx}.`);
                reject();
            });
        });
    }

    async onConnect(name) {
        var pool = this._pool[name];
        if (!pool) {
            pool = { name: name, _last: 0, conns: [] };
            this._pool[name] = pool;
        }

        if (pool.conns.length < this._pool.capacity) {
            let c = await this.onConnecting(pool._last);
            if (c) {
                pool.conns.push(c);
                pool._last = pool.conns.length;
            } else if (pool.conns.length > 0) {
                pool._last = 1;
            }
        } else if (pool._last >= this._pool.capacity) {
            pool._last = 1;
        } else {
            pool._last++;
        }

        var client = new Mongo.MongoClient(this._connstr); // 借用类型
        client = pool.conns[pool._last - 1];
        if (!client.isConnected()) await client.connect();

        return client.db(name);
    }

    /**
     * 连接数据库
     * @param {string} name  数据库名
     */
    conn(name) {
        return this.onConnect(name || this.db.db);
    }

    shutdown() {
        try {
            for (var p in this._pool) {
                if (typeof(this._pool[p]) == 'object') this._pool[p].conns.forEach(c => {
                    if (c.isConnected()) c.close();
                });
            }
        } catch (ex) {
            console.error(ex);
        }

    }
}